package com.ruoyi.common.core.redis;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;


/**
 * @author:weisn
 * @description: Redis工具类
 * @date:2018/9/3_13:34
 */
@Slf4j
@Component("mRedisUtil")
public class MRedisUtil {

    protected RedisTemplate redisTemplate;

    @Autowired(required = false)
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        RedisSerializer stringSerializer = new StringRedisSerializer();
        RedisSerializer redisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(redisSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(redisSerializer);
        this.redisTemplate = redisTemplate;
    }

    /**
     * @author:weisn
     * @description: 添加
     * @date:2018/9/3_13:38
     * @param: key
     * @param: value
     * @return:
     */
    public <T> void put(String key, T value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     *  设置值
     *
     * @author weisn
     * @param key :
     * @param value :
     * @return java.lang.Boolean
     * @date 2021/7/16 11:22
     */
    public <T> Boolean setIfAbsent(String key,T value) {
		return redisTemplate.opsForValue().setIfAbsent(key, value);
	}

	public <T> void expire(String key, int timeOut, TimeUnit minutes) {
    	redisTemplate.expire(key,timeOut,minutes);
	}




    /**
     * @author:weisn
     * @description: 添加—含有超时时间
     * @date:2018/9/3_13:38
     * @param: key
     * @param: value
     * @param: expire (默认为秒) 超时时间
     * @return:
     */
    public <T> void put(String key, T value, long expire) {
        redisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS);
    }

    /**
     * @Author: weisn
     * @Description: 将所有指定的值插入存储在键的列表的头部。如果键不存在，
     * 则在执行推送操作之前将其创建为空列表。（从右边插入）
     * @Date: 2019/12/11 15:45
     * @param
     * @return
     */
    public <T> void rightPush(String key,T value) {
        redisTemplate.opsForList().rightPush(key,value);
    }


    /**
     * @Author: weisn
     * @Description:  弹出最左边的元素，弹出之后该值在列表中将不复存在
     * @Date: 2019/12/11 15:52
     * @param
     * @return
     */
    public <T> Object getLeftPop(String key) {
        return redisTemplate.opsForList().leftPop(key);
    }

    /**
     * @author:weisn
     * @description: 添加hash
     * @date:2018/9/11_18:18
     * @param:
     * @return:
     */
    public <T> void putHash(String key, String hashKey, T hashValue) {
        redisTemplate.opsForHash().put(key, hashKey, hashValue);
    }

    public <T> void putHash(String key, String hashKey, T hashValue, long time, TimeUnit timeUnit) {
        redisTemplate.opsForHash().put(key, hashKey, hashValue);
        redisTemplate.expire(key, time, timeUnit);
    }

    /**
     * @author:weisn
     * @description: 是否hash
     * @date:2018/11/9_9:38
     * @param:
     * @return:
     */
    public boolean hasHash(String key, String hashKey) {
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }

    /**
     * @author:weisn
     * @description: 根据hashkey 获取
     * @date:2018/9/14_13:56
     * @param:
     * @return:
     */
    public <T> T getHash(String key, String hashKey) {
        return (T) redisTemplate.opsForHash().get(key, hashKey);
    }

    /**
     * @author:weisn
     * @description: 添加hash 集合
     * @date:2018/9/11_18:46
     * @param:
     * @return:
     */
    public <K, T> void pushHashAll(String key, Map<K, T> hashValue) {
        redisTemplate.opsForHash().putAll(key, hashValue);
    }


    /**
     * @author:weisn
     * @description: 添加hash 集合 带有超时时间
     * @date:2018/9/11_18:46
     * @param:
     * @return:
     */
    public <K, T> void pushHashAll(String key, Map<K, T> hashValue, long time, TimeUnit timeUnit) {
        redisTemplate.opsForHash().putAll(key, hashValue);
        redisTemplate.expire(key, time, timeUnit);
    }

    /**
     * @author:weisn
     * @description: 添加—含有超时时间
     * @date:2018/9/3_13:38
     * @param: key
     * @param: value
     * @param: expire (默认为秒) 超时时间
     * @param: 时间单位
     * @return:
     */
    public <T> void put(String key, T value, long expire, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, expire, timeUnit);
    }

    /**
     * @author:weisn
     * @description: 删除
     * @date:2018/9/3_13:41
     * @param: key
     * @return: 布尔值，成功与否
     */
    public boolean remove(String key) {
        try {
            redisTemplate.opsForValue().getOperations().delete(key);
            return true;
        } catch (Throwable t) {
            log.error("redis remove " + key + " has error,detail----" + t);
        }
        return false;
    }

    /**
     * @author:weisn
     * @description: 删除hash 根据key
     * @date:2018/9/11_18:47
     * @param: key
     * @param: hashObject
     * @return:
     */
    public <T> boolean removeHash(String key, T... hashKeys) {
        try {
            redisTemplate.opsForHash().delete(key, hashKeys);
            return true;
        } catch (Throwable t) {
            log.error("redis hash remove " + key + " has error,detail----" + t);
        }
        return false;
    }

    /**
     * @author:weisn
     * @description: 批量删除value通过key的表达式
     * @date:2018/9/3_13:44
     * @param: redis表达式
     * @return: 布尔值，成功与否
     */
    public boolean removeMatch(String match) {
        Set<String> set = redisTemplate.keys(match);
        Iterator<String> it = set.iterator();
        while (it.hasNext()) {
            String keyStr = it.next();
            try {
                redisTemplate.delete(keyStr);
            } catch (Throwable t) {
                log.error("redis remove " + keyStr + " has error,detail----" + t);
                return false;
            }
        }
        return true;
    }


    /**
     * @author:weisn
     * @description: 批量删除value通过key的表达式
     * @date:2018/9/3_13:44
     * @param: redis表达式
     * @return: 布尔值，成功与否
     */
    public int removeMatchInt(String match) {
        Set<String> set = redisTemplate.keys(match);
        Iterator<String> it = set.iterator();
        int count = 0;
        while (it.hasNext()) {
            String keyStr = it.next();
            try {
                redisTemplate.delete(keyStr);
                count = count + 1;
            } catch (Throwable t) {
                log.error("redis remove " + keyStr + " has error,detail----" + t);
            }
        }
        return count;
    }

    /**
     * @author:weisn
     * @description: 判断key是否存在
     * @date:2018/9/3_13:45
     * @param: 是否存在key
     * @return: 布尔值，是否存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Throwable t) {
            log.error("redis has key exec was error " + key + ", detail----" + t);
        }
        return false;
    }


    /**
     * @author:weisn
     * @description: 获取
     * @date:2018/9/3_13:45
     * @param: key
     * @return: 泛型对象（获取失败返回null）
     */
    public <T> T get(String key) {
        try {
            return (T) redisTemplate.opsForValue().get(key);
        } catch (Throwable t) {
            log.error("redis get key exec was error " + key + ", detail----" + t);
        }
        return null;
    }


    /**
     * @author:weisn
     * @description: hash 获取hash对象
     * @date:2018/9/12_17:38
     * @param:
     * @return:
     */
    public <T> T getHash(String key) {
        try {
            return (T) redisTemplate.opsForHash().entries(key);
        } catch (Throwable t) {
            log.error("redis get hash key exec was error " + key + ", detail----" + t);
        }
        return null;
    }


    /**
     * @author:weisn
     * @description: 将hash对象转为list
     * @date:2018/9/12_17:40
     * @param:
     * @return:
     */
    public <T> T getHashOfList(String key) {
        try {
            return (T) redisTemplate.opsForHash().values(key);
        } catch (Throwable t) {
            log.error("redis get hash list key exec was error " + key + ", detail----" + t);
        }
        return null;
    }

    public <T> Long leftPush(String key, T value) {
        return redisTemplate.opsForList().leftPush(key, value);
    }

    public <T> T rightPop(String key) {
        return (T) redisTemplate.opsForList().rightPop(key);
    }

    public Long queueSize(String key) {
        return redisTemplate.opsForList().size(key);
    }

    public Long increment(String key, long base, long delta) {
        Object v = redisTemplate.opsForValue().get(key);
        if (ObjectUtils.isEmpty(v)) {
            redisTemplate.opsForValue().set(key, base);
        }

        return redisTemplate.opsForValue().increment(key, delta);
    }


    /**
     *  删除key
     *
     * @author weisn
     * @param lockKey :
     * @return void
     * @date 2021/7/16 11:30
     */
	public void delete(String lockKey) {
		redisTemplate.delete(lockKey);
	}
}
